/*
 * Copyright 2008 Nathan C Jones
 * 
 * This file is part of Fivehundred.
 * 
 * Fivehundred is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Fivehundred is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * Fivehundred. If not, see <http://www.gnu.org/licenses/>. 
 */

package com.googlecode.fivehundred.svg;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

import com.googlecode.fivehundred.model.Card;

/**
 * Renders number cards (non face cards). Number cards are rendered by repeating
 * the suit a number of times equal to the card's face value. Ace is considered
 * a number card.
 * 
 * @author Nathan C Jones
 */
public class NumberCardRenderer extends DynamicCardRenderer {

	// There are three left-to-right suit-symbol positions on the card: left,
	// right, and center.

	/**
	 * The position of the center of the left-most suit-symbol as a ratio of the
	 * width of the card.
	 */
	private static final double POSITION_LEFT = MARGIN_WIDTH + SCALE_SUIT_MEDIUM / 2;

	/**
	 * The position of center of the right-most suit-symbol as a ratio of the
	 * width of the card.
	 */
	private static final double POSITION_RIGHT = 1.0d - MARGIN_WIDTH - SCALE_SUIT_MEDIUM / 2;

	/** The center of the card as a ratio of the card width or height. */
	private static final double POSITION_CENTER = 0.5d;

	// There are nine top-to-bottom suit-symbol positions on the card: top,
	// bottom, center, three between the top and center, and three between the
	// center and bottom.

	/**
	 * The position of the center of the top-most suit-symbol as a ratio of the
	 * height of the card.
	 */
	private static final double POSITION_TOP = MARGIN_HEIGHT + SCALE_SUIT_MEDIUM / 2;

	/**
	 * The position of the center of the bottom-most suit-symbol as a ratio of
	 * the height of the card.
	 */
	private static final double POSITION_BOTTOM = 1.0d - MARGIN_HEIGHT - SCALE_SUIT_MEDIUM / 2;

	/**
	 * The position one third of the way between the top and the bottom as a
	 * ratio of the card height.
	 */
	private static final double POSITION_LOWUPPER = POSITION_TOP + (POSITION_BOTTOM - POSITION_TOP) / 3d;

	/**
	 * The position half way between the center and the top as a ratio of the
	 * card height.
	 */
	private static final double POSITION_MIDUPPER = POSITION_TOP + (POSITION_CENTER - POSITION_TOP) / 2d;

	/**
	 * The position half way between the top and the lowupper as a ratio of the
	 * card height.
	 */
	private static final double POSITION_HIGHUPPER = POSITION_TOP + (POSITION_LOWUPPER - POSITION_TOP) / 2d;

	/**
	 * The midlower position is half way between the center and the bottom as a
	 * ratio of the card height.
	 */
	private static final double POSITION_MIDLOWER = POSITION_BOTTOM - (POSITION_BOTTOM - POSITION_CENTER) / 2d;;

	/**
	 * The highlower position is two thirds of the way between the top and the
	 * bottom as a ratio of the card height.
	 */
	private static final double POSITION_HIGHLOWER = POSITION_TOP + (POSITION_BOTTOM - POSITION_TOP) * 2d / 3d;

	/**
	 * The position half way between the bottom and highlower as a ratio of the
	 * card height.
	 */
	private static final double POSITION_LOWLOWER = POSITION_HIGHLOWER + (POSITION_BOTTOM - POSITION_HIGHLOWER) / 2d;

	// The available coordinates for suit placement:

	private static final RelativeCoordinate COORDINATE_TOP_LEFT = new RelativeCoordinate(POSITION_LEFT, POSITION_TOP);

	private static final RelativeCoordinate COORDINATE_TOP_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_TOP);

	private static final RelativeCoordinate COORDINATE_TOP_RIGHT = new RelativeCoordinate(POSITION_RIGHT, POSITION_TOP);

	private static final RelativeCoordinate COORDINATE_CENTER_LEFT = new RelativeCoordinate(POSITION_LEFT, POSITION_CENTER);

	private static final RelativeCoordinate COORDINATE_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_CENTER);

	private static final RelativeCoordinate COORDINATE_CENTER_RIGHT = new RelativeCoordinate(POSITION_RIGHT, POSITION_CENTER);

	private static final RelativeCoordinate COORDINATE_BOTTOM_LEFT = new RelativeCoordinate(POSITION_LEFT, POSITION_BOTTOM);

	private static final RelativeCoordinate COORDINATE_BOTTOM_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_BOTTOM);

	private static final RelativeCoordinate COORDINATE_BOTTOM_RIGHT = new RelativeCoordinate(POSITION_RIGHT, POSITION_BOTTOM);

	private static final RelativeCoordinate COORDINATE_HIGHLOWER_LEFT = new RelativeCoordinate(POSITION_LEFT, POSITION_HIGHLOWER);

	private static final RelativeCoordinate COORDINATE_LOWUPPER_LEFT = new RelativeCoordinate(POSITION_LEFT, POSITION_LOWUPPER);

	private static final RelativeCoordinate COORDINATE_HIGHLOWER_RIGHT = new RelativeCoordinate(POSITION_RIGHT, POSITION_HIGHLOWER);

	private static final RelativeCoordinate COORDINATE_LOWUPPER_RIGHT = new RelativeCoordinate(POSITION_RIGHT, POSITION_LOWUPPER);

	private static final RelativeCoordinate COORDINATE_MIDLOWER_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_MIDLOWER);

	private static final RelativeCoordinate COORDINATE_MIDUPPER_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_MIDUPPER);

	private static final RelativeCoordinate COORDINATE_LOWLOWER_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_LOWLOWER);

	private static final RelativeCoordinate COORDINATE_HIGHUPPER_CENTER = new RelativeCoordinate(POSITION_CENTER, POSITION_HIGHUPPER);

	// The coordinate arrays for each card number:

	private static final RelativeCoordinate[] COORDINATES_ONE = new RelativeCoordinate[] { COORDINATE_CENTER };

	private static final RelativeCoordinate[] COORDINATES_TWO = new RelativeCoordinate[] { COORDINATE_TOP_CENTER, COORDINATE_BOTTOM_CENTER };

	private static final RelativeCoordinate[] COORDINATES_THREE = new RelativeCoordinate[] { COORDINATE_TOP_CENTER, COORDINATE_CENTER,
			COORDINATE_BOTTOM_CENTER };

	private static final RelativeCoordinate[] COORDINATES_FOUR = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT };

	private static final RelativeCoordinate[] COORDINATES_FIVE = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT, COORDINATE_CENTER };

	private static final RelativeCoordinate[] COORDINATES_SIX = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT, COORDINATE_CENTER_LEFT, COORDINATE_CENTER_RIGHT };

	private static final RelativeCoordinate[] COORDINATES_SEVEN = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT, COORDINATE_CENTER_LEFT, COORDINATE_CENTER_RIGHT, COORDINATE_MIDUPPER_CENTER };

	private static final RelativeCoordinate[] COORDINATES_EIGHT = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT, COORDINATE_CENTER_LEFT, COORDINATE_CENTER_RIGHT, COORDINATE_MIDUPPER_CENTER,
			COORDINATE_MIDLOWER_CENTER };

	private static final RelativeCoordinate[] COORDINATES_NINE = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT, COORDINATE_CENTER, COORDINATE_LOWUPPER_LEFT, COORDINATE_HIGHLOWER_LEFT,
			COORDINATE_LOWUPPER_RIGHT, COORDINATE_HIGHLOWER_RIGHT };

	private static final RelativeCoordinate[] COORDINATES_TEN = new RelativeCoordinate[] { COORDINATE_TOP_LEFT, COORDINATE_BOTTOM_LEFT,
			COORDINATE_TOP_RIGHT, COORDINATE_BOTTOM_RIGHT, COORDINATE_LOWUPPER_LEFT, COORDINATE_HIGHLOWER_LEFT, COORDINATE_LOWUPPER_RIGHT,
			COORDINATE_HIGHLOWER_RIGHT, COORDINATE_HIGHUPPER_CENTER, COORDINATE_LOWLOWER_CENTER };

	/**
	 * The suit coordinates mapped to card values.
	 */
	private static final RelativeCoordinate[][] COORDINATES = new RelativeCoordinate[][] { COORDINATES_ONE, COORDINATES_TWO,
			COORDINATES_THREE, COORDINATES_FOUR, COORDINATES_FIVE, COORDINATES_SIX, COORDINATES_SEVEN, COORDINATES_EIGHT, COORDINATES_NINE,
			COORDINATES_TEN };

	/**
	 * Create a number-card renderer from the given card.
	 * 
	 * @param card the card to create a renderer for. This card must have a face
	 *        number between 1 and 10 inclusive.
	 */
	public NumberCardRenderer(final Card card) {
		super(card);
		if (card.getFace().getNumber() < 1 || card.getFace().getNumber() > 10) {
			throw new IllegalArgumentException("Card number must be between 1 and 10 inclusive.");
		}
	}

	@Override
	protected void drawCardCenter(final Graphics2D g, final int width, final int height) {
		Image suitImage = getSuitImage(getCard(), (int) (SCALE_SUIT_MEDIUM * width));
		BufferedImage invertedSuitImage = new BufferedImage(suitImage.getWidth(null), suitImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
		RelativeCoordinate[] suitLocations = COORDINATES[getCard().getFace().getNumber() - 1];

		((Graphics2D) invertedSuitImage.getGraphics()).drawImage(suitImage, AffineTransform.getRotateInstance(Math.PI, 0.5 * suitImage
				.getWidth(null), 0.5 * suitImage.getHeight(null)), null);
		for (RelativeCoordinate coordinate : suitLocations) {
			int xCoord = (int) (coordinate.x * width - 0.5 * suitImage.getWidth(null));
			int yCoord = (int) (coordinate.y * height - 0.5 * suitImage.getHeight(null));
			if (coordinate.y > 0.5) {
				g.drawImage(invertedSuitImage, xCoord, yCoord, null);
			} else {
				g.drawImage(suitImage, xCoord, yCoord, null);
			}
		}
	}

}
